﻿namespace Snipps.ViewModels.Filters
{
    using System.Collections.ObjectModel;
    using System.Linq;
    using System.Windows.Data;
    using System.Windows.Input;

    using GalaSoft.MvvmLight.Command;
    using GalaSoft.MvvmLight.Messaging;

    using Snipps.Core;
    using Snipps.Messages;

    public class CompletionListViewModel : ActiveViewModel
    {
        private readonly object _filterItemsLock = new object();

        private object _selectedItem;

        public CompletionListViewModel()
        {
            FilteredItems = new ObservableCollection<object>();

            SelectNextItemCommand = new RelayCommand(OnSelectNextItem);
            SelectFirstItemCommand = new RelayCommand(OnSelectFirstItem);
            SelectLastItemCommand = new RelayCommand(OnSelectLastItem);
            SelectPrevItemCommand = new RelayCommand(OnSelectPrevItem);
            ActivateSelectedItemCommand = new RelayCommand(OnActivateCurrentItem, CanActivateCurrentItem);
            RemoveSelectedItemCommand = new RelayCommand(OnRemoveSelectedItem, CanRemoveSelectedItem);
            EditSelectedItemCommand = new RelayCommand(OnEditSelectedItem, CanEditSelectedItem);

            BindingOperations.EnableCollectionSynchronization(FilteredItems, _filterItemsLock);
        }

        public bool IsReadOnly { get; set; }

        public ObservableCollection<object> FilteredItems { get; private set; }

        public ICommand SelectFirstItemCommand { get; private set; }

        public ICommand SelectLastItemCommand { get; private set; }

        public ICommand SelectNextItemCommand { get; private set; }

        public ICommand SelectPrevItemCommand { get; private set; }

        public ICommand ActivateSelectedItemCommand { get; private set; }

        public ICommand RemoveSelectedItemCommand { get; private set; }

        public ICommand EditSelectedItemCommand { get; private set; }

        public object SelectedItem
        {
            get
            {
                return _selectedItem;
            }

            set
            {
                SetProperty(ref _selectedItem, value, "SelectedItem");
            }
        }

        private void OnSelectLastItem()
        {
            if (FilteredItems.Any())
            {
                SelectedItem = FilteredItems.Last();
            }
        }

        private void OnSelectFirstItem()
        {
            if (FilteredItems.Any())
            {
                SelectedItem = FilteredItems[0];
            }
        }

        private bool CanActivateCurrentItem()
        {
            return SelectedItem != null;
        }

        private bool CanEditSelectedItem()
        {
            return SelectedItem != null && !IsReadOnly;
        }

        private void OnEditSelectedItem()
        {
            Messenger.Default.Send(new EditItemMsg { Item = SelectedItem });
        }

        private bool CanRemoveSelectedItem()
        {
            return SelectedItem != null && !IsReadOnly;
        }

        private void OnRemoveSelectedItem()
        {
            var newableItem = SelectedItem as INewable;

            if ((newableItem != null && !newableItem.IsNew) || newableItem == null)
            {
                var itemToRemove = SelectedItem;
                SelectedItem = GetNextItemFromList(itemToRemove);
                FilteredItems.Remove(itemToRemove);

                Messenger.Default.Send(new RemoveItemMsg { Item = itemToRemove });
            }
        }

        private void OnActivateCurrentItem()
        {
            Messenger.Default.Send(new ActivateItemMsg { Item = SelectedItem });
        }

        private object GetNextItemFromList(object item)
        {
            if (FilteredItems.Count > 0)
            {
                var nextItemIndex = (FilteredItems.IndexOf(item) + 1) % FilteredItems.Count;
                return FilteredItems[nextItemIndex];
            }

            return null;
        }

        private void OnSelectNextItem()
        {
            SelectedItem = GetNextItemFromList(SelectedItem);
        }

        private void OnSelectPrevItem()
        {
            if (FilteredItems.Count > 0)
            {
                var nextItemIndex = FilteredItems.IndexOf(SelectedItem) - 1;
                if (nextItemIndex < 0)
                {
                    nextItemIndex = FilteredItems.Count - 1;
                }

                SelectedItem = FilteredItems[nextItemIndex];
            }
        }

        public void ClearFilteredItems()
        {
            FilteredItems.Clear();
            SelectedItem = null;
        }
    }
}